package service

import (
	"context"
	"fmt"
	"mini-app/config"
	"mini-app/config/redis"
	"mini-app/internal/app/grpc/client"
	"mini-app/internal/app/grpc/protoc/devicec"
	"mini-app/internal/app/grpc/protoc/sale_adminc"
	"mini-app/internal/define"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	redisx "github.com/go-redis/redis/v8"
	"github.com/qichengzx/coordtransform"
)

type Location struct{}

func GeoRadius(longitude, latitude *float64) (geoLocation []redisx.GeoLocation, err error) {
	rdb := redis.NewDB()
	key := define.RedisGeo + config.Config.MerchantID
	var lng, lat float64
	if longitude == nil && latitude == nil {
		lng = 114.058342
		lat = 22.553623
	} else {
		lng = *longitude
		lat = *latitude
	}
	lng, lat = coordtransform.GCJ02toWGS84(lng, lat)
	geoLocation, err = rdb.GeoRadius(context.Background(), key, lng, lat, &redisx.GeoRadiusQuery{
		Radius:    100,   // 范围100km
		Unit:      "km",  // 单位km
		Sort:      "ASC", // 由近到远
		WithCoord: true,  // 返回经纬度坐标
		WithDist:  true,  // 返回距离
	}).Result()
	return
}

type RobotList struct {
	LocationID   string  `json:"location_id"`
	LocationName string  `json:"location_name"`
	FloorName    string  `json:"floor_name"`
	Addresss     string  `json:"address"`
	PositionName string  `json:"position_name"`
	RobotName    string  `json:"robot_name"`
	Longitude    float64 `json:"longitude"`
	Latitude     float64 `json:"latitude"`
	Distance     float64 `json:"distance"`
	SaleStatus   int32   `json:"sale_status"`
	OpeningHours string  `json:"opening_hours"`
	GoodsStock   int     `json:"goods_stock"`
}

// 获取最近的设备信息
// longitude,latitude 当前的经纬度
// goodsID 包含的商品id[可选]
func (Location) GetNeighborRobots(ctx context.Context, longitude, latitude *float64, goodsID string) (robotList []RobotList, err error) {
	geoLocation, err := GeoRadius(longitude, latitude)
	if len(geoLocation) == 0 || err != nil {
		return
	}

	deviceClient, deviceClientErr := client.GetAdminClient()
	if deviceClientErr != nil {
		logx.Error(ctx, "connect device grpc error", logx.Any("deviceClientErr", deviceClientErr))
		return
	}

	saleAdminClient, saleAdminClientErr := client.GetSaleAdminClient()
	if saleAdminClientErr != nil {
		logx.Error(ctx, "connect sale admin grpc error", logx.Any("saleAdminClientErr", saleAdminClientErr))
		return
	}

	for _, v := range geoLocation {
		robotID := v.Name
		// 获取设备详情
		deviceInfo, DeviceErr := deviceClient.DeviceDetail(ctx, &devicec.DeviceDetailReq{RobotId: robotID})
		if DeviceErr != nil || deviceInfo.Code != 0 {
			return
		}
		// 获取位置信息
		req := &devicec.LocationDetailReq{
			LocationId: deviceInfo.Device.LocationId,
		}
		locationDetail, locationErr := deviceClient.LocationDetail(ctx, req)
		if locationErr != nil || locationDetail.Location == nil {
			logx.Error(ctx, "get location detail error", logx.Any("locationErr", locationErr))
			return
		}
		// 设备位置名称
		positionMap, positionErr := deviceClient.DevicePositionName(ctx, &devicec.DevicePositionNameReq{
			PositionIds: []string{deviceInfo.Device.PositionId},
		})
		if positionErr != nil || positionMap == nil {
			logx.Error(ctx, "get position error", logx.Any("positionErr", positionErr))
			return
		}
		var positionName string
		if _, ok := positionMap.DevicePositionNameMap[deviceInfo.Device.PositionId]; ok {
			positionName = positionMap.DevicePositionNameMap[deviceInfo.Device.PositionId]
		}
		// 如果goodsID不为空，判断是否存在goodsID且库存不为空
		goodsAvailable := false
		goodsStock := 0
		{
			// 机器上的商品库存
			robotGoodsStockRsp, robotGoodsStockErr := saleAdminClient.GoodsUsableStock(ctx, &sale_adminc.GoodsUsableStockReq{
				RobotId: robotID,
			})
			if robotGoodsStockErr != nil || robotGoodsStockRsp == nil {
				err = errorx.New("获取商品库存信息错误", -1)
				return
			}
			for _, v := range robotGoodsStockRsp.Data {
				if v.GoodsId == goodsID && v.Stock > 0 {
					goodsAvailable = true
					goodsStock += int(v.Stock)
				}
			}
		}
		// 转换WGS84坐标系 -> 腾讯gcj02坐标系
		if goodsID == "" || (goodsID != "" && goodsAvailable) {
			longitude, latitude := coordtransform.WGS84toGCJ02(v.Longitude, v.Latitude)
			robotList = append(robotList, RobotList{
				LocationID:   deviceInfo.Device.LocationId,
				FloorName:    deviceInfo.Device.Floor,
				RobotName:    robotID,
				PositionName: positionName,
				LocationName: locationDetail.Location.Name,
				Addresss:     locationDetail.Location.Addr,
				OpeningHours: locationDetail.Location.OpeningHours,
				SaleStatus:   deviceInfo.Device.SaleStatus,
				Longitude:    longitude,
				Latitude:     latitude,
				Distance:     v.Dist,
				GoodsStock:   goodsStock,
			})
		}
	}
	return
}

type LocationInfoT struct {
	*devicec.Location
	Distance float64 `json:"distance"`
}

// 获取位置详情
func (Location) LocationInfo(ctx context.Context, robotID, salesID string, lat, lng float64) (*LocationInfoT, error) {
	deviceClient, deviceClientErr := client.GetAdminClient()
	if deviceClientErr != nil {
		logx.Error(ctx, "connect device grpc error", logx.Any("deviceClientErr", deviceClientErr))
		return nil, errorx.New("获取详情出错", -1)
	}
	var locationID string
	var DeviceDetailReq = &devicec.DeviceDetailReq{}
	if robotID != "" {
		DeviceDetailReq.RobotId = robotID
	} else if salesID != "" {
		DeviceDetailReq.IdentificationCode = salesID
	} else {
		return nil, errorx.New("设备不能为空", -1)
	}
	deviceDetail, deviceDetailErr := deviceClient.DeviceDetail(ctx, DeviceDetailReq)
	if deviceDetailErr == nil && deviceDetail.Device != nil {
		locationID = deviceDetail.Device.LocationId
	}
	if deviceDetail == nil || deviceDetail.Device == nil {
		return nil, errorx.New("设备不存在", -1)
	}
	// 获取位置信息
	req := &devicec.LocationDetailReq{
		LocationId: locationID,
	}
	locationDetail, locationErr := deviceClient.LocationDetail(ctx, req)
	if locationErr != nil || locationDetail == nil ||
		locationDetail.Code != 0 || locationDetail.Location == nil {
		logx.Error(ctx, "get location detail error", logx.Any("locationErr", locationErr))
		return nil, errorx.New("获取位置信息失败", -1)
	}
	var info LocationInfoT
	info.Location = locationDetail.Location
	// 计算距离
	if lat != 0 && lng != 0 {
		rdb := redis.NewDB()
		lng, lat = coordtransform.GCJ02toWGS84(lng, lat)
		positionKey := define.ReidsDeviceUserDist + fmt.Sprintf("%f", lat) + fmt.Sprintf("%f", lng)
		rdb.GeoAdd(context.Background(), positionKey,
			&redisx.GeoLocation{
				Name:      robotID,
				Latitude:  float64(locationDetail.Location.Lat),
				Longitude: float64(locationDetail.Location.Lng),
			},
			&redisx.GeoLocation{
				Name:      robotID,
				Latitude:  lat,
				Longitude: lng,
			},
		)
		rdb.Del(context.Background(), positionKey)
		dist, _ := rdb.GeoDist(ctx, define.ReidsDeviceUserDist, robotID, "", "km").Result()
		info.Distance = dist
	}
	return &info, nil
}
